package com.example.framework509.common.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.framework509.common.exceptions.PermissionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Calendar;
import java.util.Map;
import java.util.Set;

@Component
public class JwtUtil {

    private static RedisTemplate<String, Object> redisTemplate;

    @Autowired
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        JwtUtil.redisTemplate = redisTemplate;
    }

    private static final String SING = "!QWE!#R@RFDS(GF*YG$bygca8sdy1d";

    public static String getToken(Map<String, String> map) {
        return getToken(map, Calendar.MONTH, 8);
    }

    public static String getToken(Map<String, String> map, Integer calendarType, Integer amount) {

        Calendar instance = Calendar.getInstance();
        instance.add(calendarType, amount);

        JWTCreator.Builder builder = JWT.create();
//        map.put("createTime", String.valueOf(new Date().getTime()));
        map.forEach(builder::withClaim);

        String token = builder.withExpiresAt(instance.getTime())
                .sign(Algorithm.HMAC256(SING));

        setUserValidInRedis(map.get("userId"), token);

        return token;
    }

    public static DecodedJWT verify(String token) {
//        boolean userValidInRedis = getUserValidInRedis(token);
//        if (!userValidInRedis) throw new LogoutException();
        if (token == null) throw new PermissionException("无token");
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SING)).build();
        return verifier.verify(token);
    }

    public static Integer getIdFromToken(HttpServletRequest request) {
        DecodedJWT token = verify(request.getHeader("token"));
        Claim userId = token.getClaim("userId");
        Integer id = Integer.parseInt(userId.asString());
        return id;
    }

    private static void setUserValidInRedis(String userId, String newToken) {
        Boolean hasKey = redisTemplate.hasKey("tokenUserId:" + userId);
        if (hasKey != null && hasKey) {
            Object oldToken = redisTemplate.opsForValue().get("tokenUserId:" + userId);
            redisTemplate.opsForZSet().remove("validTokens", oldToken);
        }
        redisTemplate.opsForValue().set("tokenUserId:" + userId, newToken);
        redisTemplate.opsForZSet().add("validTokens", newToken, 1.0);
    }

    private static boolean getUserValidInRedis(String token) {
        Set<Object> validTokens = redisTemplate.opsForZSet().range("validTokens", 0, Long.MAX_VALUE);
        if (validTokens != null) {
            boolean contains = validTokens.contains(token);
            if (!contains) {
                return false;
            }
        }
        return true;
    }


}
